'''
    ShikIt is a simple text editor using SHIK for input.
'''
import sys, os

shikPath = os.path.abspath('../../../')
if shikPath not in sys.path:
    sys.path.append(shikPath)

#PyQtPath = '/usr/lib64/python/site-packages'                              
#if PyQtPath not in sys.path:                                              
#    sys.path.append(PyQtPath)                                             
from PyQt4 import QtGui, QtCore

import SHIK.keygens._abstract
import SHIK.keygens
import SHIK.devices._abstract
import SHIK.devices

import SHIK.ui.w
import SHIK.ui.view.factory as viewFactory

class KeyMapView( QtGui.QFrame):
    def __init__(self, parent):
        QtGui.QFrame.__init__(self, parent)
        
        from SHIK.keygens._abstract import Event
        self._event_to_lb = {}
        
        def add_lb(layout):
            lb = SHIK.ui.w.KeyLabel(self)
            layout.addWidget(lb)
            return lb
        
        U = QtGui.QHBoxLayout()
        for eventName in ('UL','UM','UR'):
            lb = add_lb(U)
            self._event_to_lb[Event(eventName)] = lb

        D = QtGui.QHBoxLayout()
        for eventName in ('DL','DM','DR'):
            lb = add_lb(D)
            self._event_to_lb[Event(eventName)] = lb

        S = QtGui.QHBoxLayout()
        for eventName in ('SUB',):
            lb = add_lb(S)
            self._event_to_lb[Event(eventName)] = lb
        
        L = QtGui.QVBoxLayout(self)
        L.addItem(U)
        L.addItem(D)
        L.addItem(S)
        L.addStretch(100)
        self.setLayout(L)
        
        self._started = False
        self.connect(self, QtCore.SIGNAL("destroyed()"), self.stop)
        
    def stop(self):
        if not self._started:
            return
        self._started = False
        [ d.remove_listener(self.on_action) for d in self._devices ]
    
    def start(self, devices):
        [ d.add_listener(self.on_action) for d in devices ]
        self._started = True
        #[ self.on_action(d,'') for d in devices ]
        
    def on_action(self, device, action):
        l = []
        kgs = device._keygens
        for kg in kgs:
            l.append(kg.__class__.__name__+':')
            futur = kg.get_futur_results()
            for e, r in futur.items():
                lb = self._event_to_lb[e]
                if callable(r):
                    if r.__doc__:
                        r = r.__doc__.lstrip().split(' ',1)[0]
                    else:
                        r = r.__name__
                if r is None:
                    r = ''
                    #lb.noneState.emit(QtCore.SIGNAL("entered()"))
                else:
                    pass#lb.charState.emit(QtCore.SIGNAL("entered()"))
                lb.setKey( r )

class ConfigView( QtGui.QFrame):
    def __init__(self, parent, mainWin):
        QtGui.QFrame.__init__(self, parent)
        self.mainWin = mainWin
        
        layout = QtGui.QVBoxLayout(self)
        
        # Devices
        def hook_checkBox(checkBox, device):
            def on_change(checked):
                print "Enabling device", device, checked
                device.enable(checked)
            check.on_change = on_change
        groupBox = QtGui.QGroupBox("Enabled Devices:")
        vbox = QtGui.QVBoxLayout()
        for device in mainWin.devices():
            check = QtGui.QCheckBox(device.__class__.__name__)
            if device.enabled():
                check.setChecked(True)
            hook_checkBox(check, device)
            check.connect(
                check, QtCore.SIGNAL("stateChanged(int)"), 
                check.on_change
            )
            vbox.addWidget(check)
        groupBox.setLayout(vbox)
        layout.addWidget(groupBox)
             
        # Keygens
        def hook_checkBox(checkBox, keygen, control_name):
            checkBox._keygen = keygen
            checkBox._control_name = control_name
            def update():
                checkBox.setChecked(
                    self.mainWin.is_active(
                        checkBox._keygen,checkBox._control_name
                    )[1]
                )
            checkBox.update = update
            def nextCheckState():
                self.mainWin.set_keygen(keygen, control_name)
                self.update_keygen_checks()
            checkBox.nextCheckState = nextCheckState
        self._keygen_checks = []
        for keygen in mainWin.keygens():
            groupBox = QtGui.QGroupBox(keygen.__class__.__name__)
            vbox = QtGui.QVBoxLayout()
            for name in mainWin.keygens_control_names(keygen):
                check = QtGui.QCheckBox(name)
                hook_checkBox(check, keygen, name)
                vbox.addWidget(check)
                self._keygen_checks.append(check)
            groupBox.setLayout(vbox)
            layout.addWidget(groupBox)
        self.update_keygen_checks()
        
        layout.addStretch(1)
        self.setLayout(layout)
    
    def update_keygen_checks(self):
        [ checkBox.update() for checkBox in self._keygen_checks ]
        
class AppWin(SHIK.ui.w.MainWindow):
    def __init__(self, *args):
        SHIK.ui.w.MainWindow.__init__(self, *args)
        self.resize( 600, 300 )

        # Create central widget
        self.test_edit = QtGui.QTextEdit(self)
        self.setCentralWidget(self.test_edit)
        
        # Configure initial SHIK
        self._keygen = None
#        syskb = SHIK.devices.SysKeyboard()
#        syskb.disable()
#        syskb.DEBUG(True)
        self._devices = [
            SHIK.ui.w.QTextEditDevice(self.test_edit),
#            syskb,
        ]
        
        # Declare view creators:
        viewFactory.register('KeyMap', ('Main','Help',), self._create_kmap_view)
        viewFactory.register('Config', ('Main','Help',), self._create_ConfigView)

        # Create available keygen and respective control maps
        hottyper = SHIK.keygens.HotTyper()
        KC = SHIK.devices.KeyControl
        self._controls = {
            hottyper: {
                        'AZERTY': (
                             KC("S"),
                             KC("D"),
                             KC("F"),
                             KC("Z"),
                             KC("E"),
                             KC("R"),
                             KC("Space"),
                        ),
                        'AZERTY angle': (
                             KC(QtCore.Qt.Key_D),
                             KC(QtCore.Qt.Key_F),
                             KC(QtCore.Qt.Key_V),
                             KC(QtCore.Qt.Key_R),
                             KC(QtCore.Qt.Key_T),
                             KC(QtCore.Qt.Key_G),
                             KC(QtCore.Qt.Key_Space),
                        ),
                        'QWERTY': (
                             KC(QtCore.Qt.Key_A),
                             KC(QtCore.Qt.Key_S),
                             KC(QtCore.Qt.Key_D),
                             KC(QtCore.Qt.Key_Q),
                             KC(QtCore.Qt.Key_W),
                             KC(QtCore.Qt.Key_E),
                        ),
                        'NumPad 90cw': (
                             KC(QtCore.Qt.Key_3),
                             KC(QtCore.Qt.Key_6),
                             KC(QtCore.Qt.Key_9),
                             KC(QtCore.Qt.Key_2),
                             KC(QtCore.Qt.Key_5),
                             KC(QtCore.Qt.Key_8),
                        ),
                    },
        }
        # This store a list of setted control names per keygen:
        self._active_keygen_control_names = {}
        
        # Set default keygen
        self.set_keygen(hottyper, 'AZERTY') 
        
        # Initial views:
        self._AddView('KeyMap', area=QtCore.Qt.LeftDockWidgetArea)
        self._AddView('Config', area=QtCore.Qt.RightDockWidgetArea)
        
        self.statusBar().showMessage("Welcome to SHIKit")
    
    def devices(self):
        return self._devices
    
    def keygens(self):
        return self._controls.keys()
    
    def keygens_control_names(self, keygen):
        return self._controls[keygen].keys()
    
    def set_keygen(self, keygen, controlsName):
        '''
        Change the KeyGen instance used by the SHIK.
        '''
        assert isinstance(keygen, SHIK.keygens._abstract.KeyGen)

        self._active_keygen_control_names = {}
        for d in self._devices:
            d.clear_keygens()
            d.add_keygen(keygen, self._controls[keygen][controlsName])
        
        if keygen not in self._active_keygen_control_names:
            self._active_keygen_control_names[keygen] = []
        self._active_keygen_control_names[keygen].append(controlsName)
        
    def is_active(self, keygen, control_name):
        '''
        Returns two boolean like:
            is_keygen_active, is_control_name_active_for_this_keygen
        The first has to be True for the second to be true too.
        '''
        if keygen not in self._active_keygen_control_names:
            return False, False
        return True, control_name in self._active_keygen_control_names[keygen]
    
    def on_action(self, device, action):
        print "ShikIt ears", device, action
    
    def _create_kmap_view(self, type, parent):
        kmv = KeyMapView(parent)
        kmv.start(self._devices)
        return kmv
    
    def _create_ConfigView(self, type, parent):
        cv = ConfigView(parent, self)
        return cv

def run():
    app = QtGui.QApplication(sys.argv)

    w = AppWin()
    w.show()
    
    ret = app.exec_()
    return ret


if __name__ == '__main__':
    sys.exit(run())
